package com.hmy.finance.service.core.dto;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hmy.ccp.error.exception.HMYRuntimeException;
import com.hmy.finance.api.bo.core.request.SupplementaryPauseGenerateRequest;
import com.hmy.finance.api.bo.core.request.enums.FeeTypeEnum;
import com.hmy.finance.api.bo.core.request.vos.DeviceInfoVo;
import com.hmy.finance.api.bo.core.response.SupplementaryPauseGenerateResponse;
import com.hmy.finance.common.enums.BusinessBillTypeEnum;
import com.hmy.finance.common.enums.ProfitLossStatusEnum;
import com.hmy.finance.dal.po.DeviceProfitLossDetailPo;
import com.hmy.finance.dal.po.DeviceRentalRecordPo;
import com.hmy.finance.dal.po.ProfitLossRecordPo;
import lombok.Data;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;

/**
 * 补充报停生成损益请求
 *
 * @author songkf
 * @date 2024/4/23
 */
@Data
public class SupplementaryPauseGenerateDto implements java.io.Serializable {
    private static final long serialVersionUID = 6095943419696333677L;
    //========== Request Parameters ==========
    /**
     * 客户ID
     */
    private Long customerId;
    /**
     * 合同ID
     */
    private Long contractId;
    /**
     * 业务单据ID
     */
    private Long businessBillId;
    /**
     * 补录报停设备信息
     */
    private List<DeviceInfoVo> supplementaryDeviceInfoList;
    /**
     * 补录报停总费用
     */
//    private BigDecimal supplementaryPauseTotalAmount;

    //========== Logic Process Parameters ===========
    /**
     * 设备租赁记录集合
     */
    private List<DeviceRentalRecordPo> deviceRentalRecordPoList;
    /**
     * 需要更新费用周期结束时间的设备租赁记录集合
     */
    private List<DeviceRentalRecordPo> needUpdateDeviceRentalRecordPoList = new ArrayList<>();
    /**
     * 损益记录
     */
    private ProfitLossRecordPo profitLossRecordPo;
    /**
     * 设备损益明细信息
     */
    private List<DeviceProfitLossDetailPo> deviceProfitLossRecordPoList = new ArrayList<>();

    //=============== Helper Methods ===============

    /**
     * Build and return a SupplementaryPauseGenerateDto object based on the provided SupplementaryPauseGenerateRequest.
     *
     * @param request the SupplementaryPauseGenerateRequest object
     * @return the built SupplementaryPauseGenerateDto object
     */
    public static SupplementaryPauseGenerateDto buildFromRequest(SupplementaryPauseGenerateRequest request) {
        SupplementaryPauseGenerateDto dto = new SupplementaryPauseGenerateDto();
        dto.setCustomerId(request.getCustomerId());
        dto.setContractId(request.getContractId());
        dto.setBusinessBillId(request.getBusinessBillId());
        dto.setSupplementaryDeviceInfoList(request.getSupplementaryDeviceInfoList());
//        dto.setSupplementaryPauseTotalAmount(request.getSupplementaryPauseTotalAmount());
        return dto;
    }

    /**
     * A method to build a ProfitLossRecordPo object and populate its fields.
     *
     * @param identifierGenerator the identifier generator to generate an identifier for the ProfitLossRecordPo
     */
    public void buildProfitLossRecordPo(DefaultIdentifierGenerator identifierGenerator) {
        ProfitLossRecordPo profitLossRecordPo = new ProfitLossRecordPo();
        profitLossRecordPo.setCustomerId(this.getCustomerId());
        profitLossRecordPo.setContractId(this.getContractId());
        profitLossRecordPo.setBusinessBillId(this.getBusinessBillId());
        profitLossRecordPo.setBusinessBillType(BusinessBillTypeEnum.PAUSE);
        profitLossRecordPo.setFeeType(FeeTypeEnum.SUPPLEMENTARY_PAUSE_FEE);
        //使用map累加supplementaryDeviceInfoList中的pauseFee
        BigDecimal totalFeeAmount = this.getSupplementaryDeviceInfoList().stream().map(DeviceInfoVo::getPauseFee).reduce(BigDecimal.ZERO, BigDecimal::add);
        profitLossRecordPo.setTotalFeeAmount(totalFeeAmount);
        profitLossRecordPo.setFeeIncurredTime(LocalDateTime.now());
        profitLossRecordPo.setStatus(ProfitLossStatusEnum.ALREADY_EFFECTIVE);
        profitLossRecordPo.setId(identifierGenerator.nextId(profitLossRecordPo));
        this.setProfitLossRecordPo(profitLossRecordPo);
    }

    public void buildDeviceProfitLossRecordPoList(DefaultIdentifierGenerator identifierGenerator) {
        for (DeviceInfoVo supplementaryDeviceInfo : this.getSupplementaryDeviceInfoList()) {
            //从在租设备中获取对应的设备信息
            DeviceRentalRecordPo deviceRentalRecordPo = deviceRentalRecordPoList.stream().filter(po -> po.getDeviceId().equals(supplementaryDeviceInfo.getDeviceId()) && po.getEntryFormId().equals(supplementaryDeviceInfo.getEntryFormId())).findFirst().orElse(null);
            if (deviceRentalRecordPo == null) {
                throw new HMYRuntimeException(Integer.valueOf("506000117"), new Object[]{supplementaryDeviceInfo.getDeviceNo()});
            }

            //如果设备已拥有费用周期结束时间，且费用周期结束时间早于单据提交时间，需将费用周期结束时间修改为今日23:59:59
            if (deviceRentalRecordPo.getExpenseCycleEndTime() != null && deviceRentalRecordPo.getExpenseCycleEndTime().isBefore(LocalDateTime.now())) {
                deviceRentalRecordPo.setExpenseCycleEndTime(LocalDateTime.now().toLocalDate().atTime(LocalTime.MAX));
                this.getNeedUpdateDeviceRentalRecordPoList().add(deviceRentalRecordPo);
            }
            this.getDeviceProfitLossRecordPoList().add(getDeviceProfitLossDetailPo(identifierGenerator, supplementaryDeviceInfo, deviceRentalRecordPo));
        }
    }

    private DeviceProfitLossDetailPo getDeviceProfitLossDetailPo(DefaultIdentifierGenerator identifierGenerator, DeviceInfoVo supplementaryDeviceInfo, DeviceRentalRecordPo deviceRentalRecordPo) {
        DeviceProfitLossDetailPo deviceProfitLossRecordPo = new DeviceProfitLossDetailPo();
        deviceProfitLossRecordPo.setDeviceRentalRecordId(deviceRentalRecordPo.getId());
        deviceProfitLossRecordPo.setContractId(deviceRentalRecordPo.getContractId());
        deviceProfitLossRecordPo.setContractNo(deviceRentalRecordPo.getContractExtensionInfo().getContractNo());
        deviceProfitLossRecordPo.setProfitLossRecordId(this.getProfitLossRecordPo().getId());
        deviceProfitLossRecordPo.setDeviceId(deviceRentalRecordPo.getDeviceId());
        deviceProfitLossRecordPo.setDeviceNo(deviceRentalRecordPo.getDeviceExtensionInfo().getDeviceNo());
        deviceProfitLossRecordPo.setBusinessBillType(BusinessBillTypeEnum.PAUSE);
        deviceProfitLossRecordPo.setFeeType(FeeTypeEnum.SUPPLEMENTARY_PAUSE_FEE);
        deviceProfitLossRecordPo.setFee(supplementaryDeviceInfo.getPauseFee());
        deviceProfitLossRecordPo.setDays(supplementaryDeviceInfo.getPauseDays());
        deviceProfitLossRecordPo.setFeeIncurredTime(LocalDateTime.now());
        deviceProfitLossRecordPo.setStatus(ProfitLossStatusEnum.WAIT_EFFECTIVE);
        deviceProfitLossRecordPo.setId(identifierGenerator.nextId(deviceProfitLossRecordPo));
//        //修改租赁记录表的报停天数以及计租天数
//        deviceRentalRecordPo.setTotalPauseDays(deviceRentalRecordPo.getTotalPauseDays() + supplementaryDeviceInfo.getPauseDays());
//        deviceRentalRecordPo.setTotalRentalDays(deviceRentalRecordPo.getTotalRentalDays() - supplementaryDeviceInfo.getPauseDays());
        return deviceProfitLossRecordPo;
    }

    public Wrapper<DeviceRentalRecordPo> buildDeviceRentalRecordPoLambdaQueryWrapper() {
        return Wrappers.lambdaQuery(DeviceRentalRecordPo.class)
                .eq(DeviceRentalRecordPo::getCustomerId, customerId)
                .eq(DeviceRentalRecordPo::getContractId, contractId)
                .and(wra -> {
                    for (DeviceInfoVo supplementaryDeviceInfo : supplementaryDeviceInfoList) {
                        wra.or(wrb -> wrb.eq(DeviceRentalRecordPo::getDeviceId, supplementaryDeviceInfo.getDeviceId()).eq(DeviceRentalRecordPo::getEntryFormId, supplementaryDeviceInfo.getEntryFormId()));
                    }
                });
    }

    public void assembleProfitLossRecord(DefaultIdentifierGenerator identifierGenerator) {
        buildProfitLossRecordPo(identifierGenerator);
        buildDeviceProfitLossRecordPoList(identifierGenerator);
    }

    public SupplementaryPauseGenerateResponse getResponse() {
        SupplementaryPauseGenerateResponse response = new SupplementaryPauseGenerateResponse();
        response.setProfitLossRecordId(this.getProfitLossRecordPo().getId());
        response.setResult(Boolean.TRUE);
        return response;
    }
}

